package com.cloud.client;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.cloud.bean.ServiceInfo;
import com.cloud.bean.Status;
import okhttp3.*;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.cloud.util.FileUtil.getHttpCacheDir;

public class NextGISApiClient {
    private static final String HOST = "qms.nextgis.com";
    private static final int CACHE_SIZE = 10 * 1024 * 1024;
    private final OkHttpClient httpClient;
    private final Map<Integer, Icon> iconCache = new HashMap<>();
    private static Icon defaultIcon;
    private static OkHttpClient downloadHttpClient;

    public NextGISApiClient() {
        File file = new File(getHttpCacheDir());
        httpClient = new OkHttpClient.Builder()
                .cache(new Cache(file, CACHE_SIZE)) // 配置缓存
                .addNetworkInterceptor(new NetCacheInterceptor())
                .build();
    }

    /**
     * 同步获取服务信息列表
     *
     * @param searchWord 根据名称进行查找服务列表
     * @return ServiceInfo
     */
    public List<ServiceInfo> getServiceInfo(String searchWord) throws IOException {
        List<ServiceInfo> list = new ArrayList<>();
        HttpUrl httpUrl = new HttpUrl.Builder()
                .scheme("https")
                .host(HOST)
                .addPathSegment("api/v1/geoservices")
                .addQueryParameter("search", searchWord)
                .build();
        Request request = new Request.Builder()
                .url(httpUrl)
                .get()
                .build();
        Response resp = httpClient.newCall(request).execute();
        JSONArray array = JSONArray.parseArray(Objects.requireNonNull(resp.body()).string());
        for (Object o : array) {
            JSONObject jsonInfo = JSONObject.parseObject(o.toString());
            Integer id = jsonInfo.getInteger("id");
            HttpUrl detailHttpUrl = new HttpUrl.Builder()
                    .scheme("https")
                    .host(HOST)
                    .addPathSegment("api/v1/geoservices/" + id)
                    .build();
            Request detailRequest = new Request.Builder()
                    .url(detailHttpUrl)
                    .get()
                    .build();

            Response detailInfo = httpClient.newCall(detailRequest).execute();
            JSONObject detailJsonInfo = JSONObject.parseObject(Objects.requireNonNull(detailInfo.body()).string());
            Status status = Status.UNKNOWN;
            for (Status s : Status.values()) {
                if (s.getStatus().equals(detailJsonInfo.getString("cumulative_status"))) {
                    status = s;
                    break;
                }
            }
            Icon icon = getIcon(detailJsonInfo.getInteger("icon"));
            String url = detailJsonInfo.getString("type").equals("tms")
                    ?detailJsonInfo.getString("origin_url")
                    :detailJsonInfo.getString("url");
            ServiceInfo serviceInfo = new ServiceInfo(
                    id,
                    detailJsonInfo.getString("name"),
                    detailJsonInfo.getString("desc"),
                    getServiceURL(id),
                    status,
                    url,
                    detailJsonInfo.getString("epsg"),
                    detailJsonInfo.getString("type"),
                    icon
            );
            list.add(serviceInfo);
        }
        return list;
    }

    /**
     * 获取服务的url
     *
     * @param id
     * @return url
     */
    public String getServiceURL(int id) {
        return new HttpUrl.Builder()
                .scheme("https")
                .host(HOST)
                .addPathSegment("/geoservices/" + id)
                .build().toString();
    }

    public Icon getIcon(Integer id) throws IOException {
        if (id == null) {
            if (defaultIcon == null) {
                Request request = new Request.Builder()
                        .url("https://qms.nextgis.com/api/v1/icons/default")
                        .get()
                        .build();
                Response response = httpClient.newCall(request).execute();
                InputStream is = Objects.requireNonNull(response.body()).byteStream();
                BufferedImage img = ImageIO.read(is);
                is.close();
                defaultIcon = new ImageIcon(img);
            }
            return defaultIcon;
        }
        if (iconCache.get(id) != null) {
            return iconCache.get(id);
        } else {
            Request request = new Request.Builder()
                    .url("https://qms.nextgis.com/api/v1/icons/" + id + "/content")
                    .get()
                    .build();
            Response response = httpClient.newCall(request).execute();
            InputStream is = Objects.requireNonNull(response.body()).byteStream();
            BufferedImage img = ImageIO.read(is);
            is.close();
            ImageIcon icon = new ImageIcon(img);
            iconCache.put(id, icon);
            return icon;
        }
    }

    /**
     * https://{switch:a,b,c}.tile.xxx 这种格式的TMS需要替换
     * @param url 字符串
     */
    public static List<String> parseTmsURL(String url) {
        List<String> urls = new ArrayList<>();
        Pattern compile = Pattern.compile("\\{switch:[^}]*}");
        Matcher matcher = compile.matcher(url);
        List<String> switches = new ArrayList<>();
        while (matcher.find()) {
            switches.add(url.substring(matcher.start(), matcher.end()));
        }
        if (switches.size() == 0) {
            urls.add(url);
            return urls;
        }
        String url_pattern = url;
        List<String[]> switch_variants = new ArrayList<>();
        for (String str : switches) {
            url_pattern = url_pattern.replace(str, "%s");
            switch_variants.add(str.substring(8, str.length() - 1).split(","));
        }
        for (String[] switch_variant : switch_variants) {
            for (String s : switch_variant) {
                urls.add(url_pattern.replace("%s", s));
            }
        }
        return urls;
    }

    /**
     * 下载geoJSON数据
     *
     * @param url 链接
     * @param file 存储的文件
     * @param callback 进度监听器
     * @return 是否成功
     * @throws IOException io错误
     */
    public static boolean downloadGeoJSON(String url, File file, ProgressListener callback) throws IOException {
        if (downloadHttpClient == null) {
            downloadHttpClient = new OkHttpClient.Builder()
                    .addInterceptor(new ProgressResponseInterceptor(callback))
                    .build();
        }
        Request geoRequest = new Request.Builder()
                .url(url)
                .get()
                .addHeader("Accept-Encoding", "identity") // 不走gzip，不然不好拿下载的文件总长度
                .build();
        ResponseBody body = downloadHttpClient.newCall(geoRequest).execute().body();
        if (body == null) {
            return false;
        }
        try (InputStream is = body.byteStream();
             FileOutputStream fos = new FileOutputStream(file)) {
            byte[] buf = new byte[4096];
            int len;
            while ((len = is.read(buf)) != -1) {
                fos.write(buf, 0, len);
            }
        } catch (IOException E1) {
            return false;
        }
        return true;
    }
}

